package com.example.duihua.websocket;

import com.example.duihua.entity.Message;
import com.example.duihua.entity.User;
import com.example.duihua.security.JwtTokenProvider;
import com.example.duihua.service.MessageService;
import com.example.duihua.service.UserService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
    private static final AttributeKey<Long> USER_ID_KEY = AttributeKey.valueOf("userId");
    
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private MessageService messageService;
    
    @Autowired
    private WebSocketSessionManager sessionManager;

    @Autowired
    private com.example.duihua.service.ConversationService conversationService;
    
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        String text = frame.text();
        JsonNode jsonNode = objectMapper.readTree(text);
        
        String type = jsonNode.get("type").asText();
        JsonNode data = jsonNode.get("data");
        
        switch (type) {
            case "AUTH":
                handleAuth(ctx, data);
                break;
            case "MESSAGE":
                handleMessage(ctx, data);
                break;
            case "STATUS":
                handleStatus(ctx, data);
                break;
            case "TYPING":
                handleTyping(ctx, data);
                break;
            case "JOIN_GROUP":
                handleJoinGroup(ctx, data);
                break;
            case "LEAVE_GROUP":
                handleLeaveGroup(ctx, data);
                break;
            default:
                logger.warn("未知的消息类型: {}", type);
        }
    }

    private void handleAuth(ChannelHandlerContext ctx, JsonNode data) {
        try {
            String token = data.get("token").asText();
            if (jwtTokenProvider.validateToken(token)) {
                String username = jwtTokenProvider.getUsernameFromJWT(token);
                User user = userService.findByUsername(username);
                
                if (user != null) {
                    // 将用户ID绑定到Channel
                    ctx.channel().attr(USER_ID_KEY).set(user.getId());
                    
                    // 注册会话
                    sessionManager.register(user.getId(), ctx.channel());
                    
                    // 更新用户状态为在线
                    userService.updateStatus(user.getId(), "ONLINE");
                    
                    // 发送认证成功响应
                    Map<String, Object> response = new HashMap<>();
                    response.put("success", true);
                    response.put("userId", user.getId());
                    
                    Map<String, Object> authResponse = new HashMap<>();
                    authResponse.put("type", "AUTH_RESPONSE");
                    authResponse.put("data", response);
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(
                            objectMapper.writeValueAsString(authResponse)
                    ));
                    
                    // 广播用户上线状态
                    broadcastStatus(user.getId(), "ONLINE");
                    
                    logger.info("用户认证成功: {}", username);
                } else {
                    sendError(ctx, "用户不存在");
                }
            } else {
                sendError(ctx, "无效的令牌");
            }
        } catch (Exception e) {
            logger.error("认证处理错误", e);
            sendError(ctx, "认证失败");
        }
    }

    private void handleMessage(ChannelHandlerContext ctx, JsonNode data) {
        try {
            Long senderId = ctx.channel().attr(USER_ID_KEY).get();
            if (senderId == null) {
                sendError(ctx, "未认证");
                return;
            }
            
            Message message = new Message();
            message.setSenderId(senderId);
            message.setReceiverId(data.get("receiverId").asLong());
            message.setType(data.get("chatType").asText());
            message.setContentType(data.get("contentType").asText());
            message.setContent(data.get("content").toString());
            message.setStatus("SENT");
            message.setCreatedAt(new Date());
            
            // 构建统一的会话ID（便于前后端稳定匹配）
            if ("PRIVATE".equals(message.getType())) {
                Long a = Math.min(senderId, message.getReceiverId());
                Long b = Math.max(senderId, message.getReceiverId());
                message.setConversationId("private_" + a + "_" + b);
            } else {
                message.setConversationId("group_" + message.getReceiverId());
            }
            
            // 保存消息
            Message savedMessage = messageService.save(message);
            
            // 发送消息给接收者
            if ("PRIVATE".equals(message.getType())) {
                // 私聊消息
                Map<String, Object> privateMessage = new HashMap<>();
                privateMessage.put("type", "MESSAGE");
                privateMessage.put("data", savedMessage);
                sessionManager.sendToUser(message.getReceiverId(), privateMessage);
            } else {
                // 群聊消息
                Map<String, Object> groupMessage = new HashMap<>();
                groupMessage.put("type", "MESSAGE");
                groupMessage.put("data", savedMessage);
                sessionManager.sendToGroup(message.getReceiverId(), groupMessage, senderId);
            }
            
            // 发送确认消息给发送者
            Map<String, Object> ackData = new HashMap<>();
            ackData.put("messageId", savedMessage.getId());
            ackData.put("status", "SENT");
            
            Map<String, Object> ackMessage = new HashMap<>();
            ackMessage.put("type", "MESSAGE_ACK");
            ackMessage.put("data", ackData);
            
            ctx.channel().writeAndFlush(new TextWebSocketFrame(
                    objectMapper.writeValueAsString(ackMessage)
            ));

            // 更新双方会话的最后一条消息与时间、未读计数
            try {
                updateConversations(savedMessage, senderId);
            } catch (Exception ex) {
                logger.error("更新会话摘要失败", ex);
            }
            
        } catch (Exception e) {
            logger.error("消息处理错误", e);
            sendError(ctx, "消息发送失败");
        }
    }

    private void updateConversations(Message savedMessage, Long senderId) {
        String plainLastMessage = extractPlainText(savedMessage.getContent());
        Date lastTime = savedMessage.getCreatedAt();

        if ("PRIVATE".equals(savedMessage.getType())) {
            Long receiverId = savedMessage.getReceiverId();
            Long a = Math.min(senderId, receiverId);
            Long b = Math.max(senderId, receiverId);
            String convIdDb = a + "_" + b; // 数据库中的会话ID（无前缀）

            // 更新发送者会话：未读为0
            com.example.duihua.entity.Conversation senderConv = new com.example.duihua.entity.Conversation();
            senderConv.setId(convIdDb);
            senderConv.setUserId(senderId);
            senderConv.setTargetId(senderId.equals(a) ? b : a);
            senderConv.setType("PRIVATE");
            senderConv.setLastMessage(plainLastMessage);
            senderConv.setLastTime(lastTime);
            senderConv.setUnreadCount(0);
            conversationService.saveOrUpdate(senderConv);

            // 更新接收者会话：未读 +1
            com.example.duihua.entity.Conversation existed = conversationService.findByIdAndUserId(convIdDb, receiverId);
            int newUnread = existed != null && existed.getUnreadCount() != null ? existed.getUnreadCount() + 1 : 1;
            com.example.duihua.entity.Conversation receiverConv = new com.example.duihua.entity.Conversation();
            receiverConv.setId(convIdDb);
            receiverConv.setUserId(receiverId);
            receiverConv.setTargetId(receiverId.equals(a) ? b : a);
            receiverConv.setType("PRIVATE");
            receiverConv.setLastMessage(plainLastMessage);
            receiverConv.setLastTime(lastTime);
            receiverConv.setUnreadCount(newUnread);
            conversationService.saveOrUpdate(receiverConv);

        } else if ("GROUP".equals(savedMessage.getType())) {
            Long groupId = savedMessage.getReceiverId();
            String convIdDb = "group_" + groupId;

            // 更新发送者群会话：未读0
            com.example.duihua.entity.Conversation senderConv = new com.example.duihua.entity.Conversation();
            senderConv.setId(convIdDb);
            senderConv.setUserId(senderId);
            senderConv.setTargetId(groupId);
            senderConv.setType("GROUP");
            senderConv.setLastMessage(plainLastMessage);
            senderConv.setLastTime(lastTime);
            senderConv.setUnreadCount(0);
            conversationService.saveOrUpdate(senderConv);

            // 群成员未读的递增可依据业务：此处仅更新在线接收方（如需全量，可查询群成员列表并循环更新）
        }
    }

    private String extractPlainText(String rawContent) {
        if (rawContent == null) return "";
        try {
            JsonNode node = objectMapper.readTree(rawContent);
            if (node.isTextual()) {
                return node.asText();
            }
            if (node.has("text")) {
                return node.get("text").asText("");
            }
            return node.toString();
        } catch (Exception e) {
            // rawContent 可能是已加引号的字符串，例如 "你好"
            try {
                return objectMapper.readValue(rawContent, String.class);
            } catch (Exception ignore) {
                return rawContent;
            }
        }
    }

    private void handleStatus(ChannelHandlerContext ctx, JsonNode data) {
        try {
            Long userId = ctx.channel().attr(USER_ID_KEY).get();
            if (userId == null) {
                sendError(ctx, "未认证");
                return;
            }
            
            String status = data.get("status").asText();
            userService.updateStatus(userId, status);
            
            // 广播状态变化
            broadcastStatus(userId, status);
            
        } catch (Exception e) {
            logger.error("状态处理错误", e);
            sendError(ctx, "状态更新失败");
        }
    }

    private void handleTyping(ChannelHandlerContext ctx, JsonNode data) {
        try {
            Long userId = ctx.channel().attr(USER_ID_KEY).get();
            if (userId == null) {
                sendError(ctx, "未认证");
                return;
            }
            
            Long receiverId = data.get("receiverId").asLong();
            String chatType = data.get("chatType").asText();
            
            if ("PRIVATE".equals(chatType)) {
                // 私聊正在输入
                Map<String, Object> typingData = new HashMap<>();
                typingData.put("userId", userId);
                typingData.put("typing", true);
                
                Map<String, Object> typingMessage = new HashMap<>();
                typingMessage.put("type", "TYPING");
                typingMessage.put("data", typingData);
                
                sessionManager.sendToUser(receiverId, typingMessage);
            } else {
                // 群聊正在输入
                Map<String, Object> groupTypingData = new HashMap<>();
                groupTypingData.put("userId", userId);
                groupTypingData.put("groupId", receiverId);
                groupTypingData.put("typing", true);
                
                Map<String, Object> groupTypingMessage = new HashMap<>();
                groupTypingMessage.put("type", "TYPING");
                groupTypingMessage.put("data", groupTypingData);
                
                sessionManager.sendToGroup(receiverId, groupTypingMessage, userId);
            }
            
        } catch (Exception e) {
            logger.error("输入状态处理错误", e);
        }
    }

    private void handleJoinGroup(ChannelHandlerContext ctx, JsonNode data) {
        try {
            Long userId = ctx.channel().attr(USER_ID_KEY).get();
            if (userId == null) {
                sendError(ctx, "未认证");
                return;
            }
            Long groupId = data.get("groupId").asLong();
            sessionManager.joinGroup(userId, groupId);
        } catch (Exception e) {
            logger.error("加入群组处理错误", e);
            sendError(ctx, "加入群组失败");
        }
    }

    private void handleLeaveGroup(ChannelHandlerContext ctx, JsonNode data) {
        try {
            Long userId = ctx.channel().attr(USER_ID_KEY).get();
            if (userId == null) {
                sendError(ctx, "未认证");
                return;
            }
            Long groupId = data.get("groupId").asLong();
            sessionManager.leaveGroup(userId, groupId);
        } catch (Exception e) {
            logger.error("离开群组处理错误", e);
        }
    }

    private void broadcastStatus(Long userId, String status) {
        try {
            sessionManager.broadcastStatus(userId, status);
        } catch (Exception e) {
            logger.error("广播状态错误", e);
        }
    }

    private void sendError(ChannelHandlerContext ctx, String message) {
        try {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("message", message);
            
            Map<String, Object> errorMessage = new HashMap<>();
            errorMessage.put("type", "ERROR");
            errorMessage.put("data", errorData);
            
            ctx.channel().writeAndFlush(new TextWebSocketFrame(
                    objectMapper.writeValueAsString(errorMessage)
            ));
        } catch (Exception e) {
            logger.error("发送错误消息失败", e);
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        logger.info("客户端连接: {}", ctx.channel().remoteAddress());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        Long userId = ctx.channel().attr(USER_ID_KEY).get();
        if (userId != null) {
            // 更新用户状态为离线
            userService.updateStatus(userId, "OFFLINE");
            
            // 注销会话
            sessionManager.unregister(userId);
            
            // 广播用户下线状态
            broadcastStatus(userId, "OFFLINE");
            
            logger.info("用户断开连接: {}", userId);
        }
        logger.info("客户端断开连接: {}", ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("WebSocket异常", cause);
        ctx.close();
    }
}